/*******************************************************************************

  Pilot Intelligence Library
    http://www.pilotintelligence.com/

  ----------------------------------------------------------------------------

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.

*******************************************************************************/

#ifndef __NETWORK_UTILS_H__
#define __NETWORK_UTILS_H__

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include <string>
#include <vector>

#include "base/types/ByteOrder.h"
#include "Socket++.h"

namespace pi {


class MACAddress
{
public:
    MACAddress() {}
    virtual ~MACAddress() {}

    std::string toString(void) {
        int n = address.size();

        char addr[64];
        memset(addr, 0, 64);

        for(int i=0; i<n; i++) {
            if( i != 0 )
                sprintf(addr, "%s:%02X", addr, address[i]);
            else
                sprintf(addr, "%s%02X",  addr, address[i]);
        }

        return addr;
    }

    std::string toStringCompact(void) {
        int n = address.size();

        char addr[64];
        memset(addr, 0, 64);

        for(int i=0; i<n; i++) {
            sprintf(addr, "%s%02X", addr, address[i]);
        }

        return addr;
    }

    int fromString(const std::string& add) {
        int n = add.size();
        unsigned char u, ua[8];
        int j = 0, k;

        memset(ua, 0, 8);

        for(int i=0; i<n; i++) {
            char c = add[i];

            if( c >= 'a' && c <= 'f' ) {
                u = c - 'a' + 10;
            } else if ( c >= 'A' && c <= 'F' ) {
                u = c - 'A' + 10;
            } else if ( c >= '0' && c <= '9' ) {
                u = c - '0';
            } else {
                continue;
            }

            k = j / 2;

            if( j % 2 == 0 )
                ua[k] = ua[k] | u<<4;
            else
                ua[k] = ua[k] | u;

            j++;

            if( j >= 12 ) break;
        }

        address.clear();
        for(int i=0; i<6; i++) address.push_back(ua[i]);

        return 0;
    }

    std::vector<unsigned char> getBinAddress(void) {
        return address;
    }

    int isValid(void) {
        if( address.size() < 6 ) return 0;

        int nz = 0;
        for(int i=0; i<address.size(); i++) {
            if( address[i] ) nz++;
        }
        if( nz < 2 ) return 0;

        return 1;
    }

    MACAddress& operator = (const std::vector<unsigned char>& a) {
        address = a;
        return *this;
    }


private:
    std::vector<unsigned char>      address;
};

////////////////////////////////////////////////////////////////////////////////
/// Network interface
////////////////////////////////////////////////////////////////////////////////

class NetworkInterface
{
public:
    typedef std::vector<NetworkInterface>   NetworkInterfaceList;

public:
    NetworkInterface();
    virtual ~NetworkInterface();

    NetworkInterface& operator = (const NetworkInterface& interface_) {
        m_name              = interface_.m_name;
        m_displayName       = interface_.m_displayName;
        m_address           = interface_.m_address;
        m_subnetAddress     = interface_.m_subnetAddress;
        m_broadcastAddress  = interface_.m_broadcastAddress;
        m_macAddress        = interface_.m_macAddress;
        m_supportsIPv4      = interface_.m_supportsIPv4;
        m_supportsIPv6      = interface_.m_supportsIPv6;

        return *this;
    }

    const std::string& name(void) const {
        return m_name;
    }

    const std::string& displayName(void) const {
        return m_displayName;
    }

    const RSocketAddress& address(void) const {
        return m_address;
    }

    const RSocketAddress& subnetAddress(void) const {
        return m_subnetAddress;
    }

    const RSocketAddress& broadcastAddress(void) const {
        return m_broadcastAddress;
    }

    const MACAddress& macAddress(void) const {
        return m_macAddress;
    }

    std::string macAddress(void) {
        return m_macAddress.toString();
    }

    std::string macAddressCompact(void) {
        return m_macAddress.toStringCompact();
    }

    int macAddressIsValid(void) {
        return m_macAddress.isValid();
    }

    int supportsIPv4(void) const {
        return m_supportsIPv4;
    }

    int supportsIPv6(void) const {
        return m_supportsIPv6;
    }

    static NetworkInterfaceList list();

    static int listMACs(std::vector<MACAddress>& macAddress);

protected:
    std::string         m_name;
    std::string         m_displayName;

    RSocketAddress      m_address;
    RSocketAddress      m_subnetAddress;
    RSocketAddress      m_broadcastAddress;

    MACAddress          m_macAddress;

    int                 m_supportsIPv4;
    int                 m_supportsIPv6;
};

} // end of namespace pi

#endif // end of __NETWORK_UTILS_H__

